<template>
    <div class="left">
        <div class="container">
            <template v-for="(row, i) in existing" :key="String(Date.now())+i">
                <template v-for="(n, j) in row" :key="String(Date.now())+i+j">
                    <div class="block" :class="getClass(n, i, j)">
                    </div>
                </template>
            </template>
            <div class="game-over" v-if="store.over">
                <span>GAME OVER</span>
            </div>
        </div>
    </div>
</template>

<script setup lang="ts">
import { onMounted, ref, watch, onUnmounted } from 'vue'
import tetriStore from '@/store/tetris'
import { deepCopy, merge, isCollided, clearRow } from '@/utils/utils'
import Tetris from '@/composable/tetrisBlocks'

const store = tetriStore()
const current = ref<Tetris>()
const container = ref<number[][]>(new Array(20).fill(0).map(_ => new Array(10).fill(0)))
const existing = ref<number[][]>(new Array(20).fill(0).map(_ => new Array(10).fill(0)))
const prev = ref(0)
const clears = ref<number[]>([])
const isAuto = ref(false)
const isDown = ref(false)

function getClass(n: number, row: number, col: number): string {
    const clear = clears.value.includes(row * 10 + col) ? " clear" : ""
    return 'block' + n + clear
}
watch(store, async (val) => {
    if (val.play) {
        if (store.list.length < 2) {
            store.makeNext()
        }
        if (!current.value) {
            current.value = store.current
        }
        existing.value = merge(deepCopy(container.value), current.value!)
        requestAnimationFrame(await autoDown)
    }
    if (!val.play && !val.over) {
        current.value = undefined
        existing.value = new Array(20).fill(0).map(_ => new Array(10).fill(0))
        container.value = new Array(20).fill(0).map(_ => new Array(10).fill(0))
    }
    if (!val.play && val.over) {
        container.value = new Array(20).fill(0).map(_ => new Array(10).fill(0))
    }
})

async function autoDown(timestamp: number) {
    let step = Math.max(1000 - store.level * 40, 140)
    if (timestamp - prev.value >= step) {
        prev.value = timestamp
        isAuto.value = true
        await actions('move', 0, 1)
        isAuto.value = false
    }
    if (store.play && !store.over && !clears.value.length) {
        requestAnimationFrame(await autoDown)
    }
}
// function autoDown() {
//     if (!sto.value) {
//         let timeCount = 0
//         sto.value = setInterval(async () => {
//             const step = 25 - store.level
//             if (timeCount++ > step) {
//                 console.log('autoDown')
//                 timeCount = 0
//                 await actions('move', 0, 1)
//             }
//         }, 40)
//     }
// }

async function actions(type: 'move' | 'rotate', col = 0, row = 0) {
    const ro = type == 'rotate'
    if (!ro && col == 0 && row == 0 && isAuto.value == isDown.value) return
    if (col == 0 && row == 1 && !ro && isCollided(current.value!, container.value, col, row, ro)) {
        if (current.value!.position.row < 0) {
            // console.log(container.value, current.value)
            store.over = true
            store.play = false
            return
        }
        const num = clearRow(existing.value)
        if (num.length) {
            store.source += Math.floor((num.length / 10) * 10)
            store.level = Math.floor(store.source / 100)
            clears.value = num
            await function () {
                return new Promise((resolve, _) => {
                    setTimeout(() => {
                        resolve(true)
                    }, 500)
                })
            }()
            for (let i = 0; i < existing.value.length; i++) {
                if (clears.value.includes(i * 10)) {
                    existing.value.splice(i, 1)
                    existing.value.unshift(new Array(10).fill(0))
                }
            }
        }
        container.value = deepCopy(existing.value)
        clears.value = []
        current.value = store.footer()
    } else {
        if (isCollided(current.value!, container.value, col, row, ro)) return
        ro ? current.value?.rotate() : current.value?.move(col, row)
    }
}

function eventHandler(e: KeyboardEvent) {
    if (!store.play || clears.value.length) return
    switch (e.key) {
        case 'ArrowLeft':
            e.preventDefault()
            actions('move', -1, 0)
            break
        case 'ArrowRight':
            e.preventDefault()
            actions('move', 1, 0)
            break
        case 'ArrowDown':
            e.preventDefault()
            isDown.value = true
            actions('move', 0, 1)
            isDown.value = false
            break
        case 'ArrowUp':
            e.preventDefault()
            actions('rotate')
            break
        case "Enter":
            e.preventDefault()
            break
    }
}

onMounted(() => {
    document.addEventListener('keydown', eventHandler)
})
onUnmounted(() => {
    document.removeEventListener('keydown', eventHandler)
})
</script>

<style lang="scss" scoped>
.left {
    width: 65%;
    align-self: stretch;
    border: 1px solid var(--border-color);

    .container {
        width: calc(var(--block-side) * 10 + 11px);
        height: calc(var(--block-side) * 20 + 21px);
        display: flex;
        flex-wrap: wrap;
        background-image: var(--block-bg);
        background-size: calc(var(--block-side) + 1px) calc(var(--block-side) + 1px);
        gap: 1px;
        overflow: hidden;
        margin: 20px auto;
        border: 1px solid var(--border-color);

        .game-over {
            position: absolute;
            left: 0;
            right: 0;
            top: 0;
            bottom: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            background: #00000080;

            span {
                font-size: 32px;
                font-weight: 700;
                color: #fa7979;
                text-shadow: 0 0 10px #ff0000;
            }
        }
    }
}
</style>